package com.dxtan90.main;

import com.dxtan90.bean.RGB;
import com.dxtan90.gray.GrayMethod;
import com.dxtan90.gray.impl.AverageMethod;
import com.dxtan90.gray.impl.BiggestMethod;
import com.dxtan90.gray.impl.PowerMethod;
import com.dxtan90.gray.impl.SmallestMethod;
import com.dxtan90.util.FormatUtil;
import com.dxtan90.util.ImageUtil;
import com.dxtan90.util.RGBUtil;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class DoMain {
    private Set<GrayMethod> grayMethods = new LinkedHashSet<>();

    /**
     * 查看灰度图片
     */
    private final String COMMAND_LOOK_GRAY = "LG";
    /**
     * 转化为字符图片
     */
    private final String COMMAND_TRANSFER_STR = "TS";
    /**
     * 指令指南
     */
    private final String COMMAND_HELP = "HELP";
    /**
     * 取行最大值方式获取字符集
     */
    private final String MAX_IMG2STR = "MAX";
    /**
     * 取图片压缩方式获取字符集
     */
    private final String ZIP_IMG2STR = "ZIP";

    /**
     * 字符画数组
     */
    private final char[] CHAR_ARR = {' ', '.', ',', ':', ';', 'i', 'l', 'j', 't', 'f', 'L', 'D', 'G', 'E', 'W', '#', '@'};

    public DoMain() {
        grayMethods.add(new AverageMethod());
        grayMethods.add(new BiggestMethod());
        grayMethods.add(new PowerMethod());
        grayMethods.add(new SmallestMethod());
    }


    public static void main(String[] args) {
        DoMain doMain = new DoMain();
        if (args.length < 1) {
            System.out.println("参数有误！！！");
            return;
        }
        String command = args[0];
        if (command != null) {
            String order = command.toUpperCase().trim();
            if (!doMain.COMMAND_HELP.equals(order) && args.length < 2) {
                System.out.println("参数有误！！！");
                return;
            }
            //灰度处理命令
            if (doMain.COMMAND_LOOK_GRAY.equals(order)) {
                String inputPath = args[1];
                String outPath = "";
                if (args.length == 3) {
                    outPath = args[2];
                }
                doMain.grayOrder(inputPath, outPath);
                //字符画转换命令
            } else if (doMain.COMMAND_TRANSFER_STR.equals(order)) {
                String inputPath = args[1];
                String strMethod = "";
                if (args.length >= 3) {
                    strMethod = args[2];
                }
                String grayMethod = "";
                if (args.length >= 4) {
                    grayMethod = args[3];
                }
                String outPath = "";
                if (args.length == 5) {
                    outPath = args[4];
                }
                doMain.strOrder(inputPath, outPath, grayMethod, strMethod);
            } else if (doMain.COMMAND_HELP.equals(order)) {
                doMain.help();
            } else {
                System.out.println("命令不存在！！！");
            }
        } else {
            System.out.println("命令不存在！！！");
        }
    }

    /**
     * @param inputPath: 输入文件路径
     * @param outPath:   输出文件夹路径
     * @return: void
     * @author: shijunhao
     * @date: 2021/11/15 15:17
     * @description: 灰度处理方式
     */
    public void grayOrder(String inputPath, String outPath) {
        File file = new File(inputPath);
        String fileName = file.getName().substring(0, file.getName().lastIndexOf('.')) + "_" + "GRAY";
        if (!FormatUtil.isImage(file)) {
            System.out.println("文件格式不正确！！！");
            return;
        }
        File dir = new File(outPath + "\\" + fileName);
        if (!dir.exists()) {
            boolean mkdir = dir.mkdirs();
            if (!mkdir) {
                System.out.println("输出文件夹创建失败！！！");
                return;
            }
        }

        BufferedImage img;
        try {
            img = ImageIO.read(file);
        } catch (IOException e) {
            System.out.println("文件读取失败");
            return;
        }
        for (GrayMethod method : grayMethods) {
            BufferedImage bufferedImage = dealImage(img, method);
            writeImage(bufferedImage, dir, method.getName(), file.getName());
        }
    }

    /**
     * @param inputPath:  输入文件路径
     * @param outPath:    输出文件路径
     * @param grayMethod: 灰度处理方法
     * @param strMethod:  图片转字符处理方式
     * @return: void
     * @author: wxt.shijunhao
     * @date: 2021/11/15 16:49
     * @description: 字符画处理方式
     */
    public void strOrder(String inputPath, String outPath, String grayMethod, String strMethod) {
        GrayMethod useMethod = new AverageMethod();
        String name = grayMethod + "_";
        for (GrayMethod method : grayMethods) {
            if (name.equals(method.getName())) {
                useMethod = method;
                break;
            }
        }
        File img = new File(inputPath);
        if (!FormatUtil.isImage(img)) {
            System.out.println("文件格式不正确！！！");
            return;
        }
        String fileName = img.getName().substring(0, img.getName().lastIndexOf('.'));
        File dir = new File(outPath);
        dir = new File(dir.getAbsolutePath());
        if (!dir.exists()) {
            boolean mkdir = dir.mkdirs();
            if (!mkdir) {
                System.out.println("输出文件夹创建失败！！！");
                return;
            }
        }
        try {
            List<String> lines = null;
            if (ZIP_IMG2STR.equals(strMethod)) {
                lines = zipImgDeal(img, useMethod);
            } else if (MAX_IMG2STR.equals(strMethod)) {
                lines = maxImgDeal(img, useMethod);
            } else {
                lines = zipImgDeal(img, useMethod);
            }
            writeTxt(lines, dir, name, fileName);
        } catch (IOException e) {
            System.out.println("读取文件失败！！！");
        }
    }

    /**
     * @param img:       图片文件
     * @param useMethod: 灰度算法
     * @return: java.util.List<java.lang.String>
     * @author: shijunhao
     * @date: 2022/10/9 16:21
     * @description: 取压缩图片方式获取字符集，缺点是清晰度不高
     */
    private List<String> zipImgDeal(File img, GrayMethod useMethod) throws IOException {
        List<String> lines = new ArrayList<>();
        BufferedImage zipImg = ImageUtil.zipImg(ImageIO.read(img));
        BufferedImage image = dealImage(zipImg, useMethod);
        for (int i = 0; i < image.getHeight(); i++) {
            StringBuilder line = new StringBuilder();
            for (int j = 0; j < image.getWidth(); j++) {
                int color = image.getRGB(j, i);
                int grey = RGBUtil.ColorToRGB(color).r;
                line.append(CHAR_ARR[grey * CHAR_ARR.length / 256]).append(CHAR_ARR[grey * CHAR_ARR.length / 256]);
            }
            lines.add(line.toString());
        }
        return lines;
    }

    /**
     * @param img:       图片文件
     * @param useMethod: 灰度算法
     * @return: java.util.List<java.lang.String>
     * @author: shijunhao
     * @date: 2022/10/9 16:21
     * @description: 取最大行值方式获取字符集，缺点是纵横比不均匀
     */
    private List<String> maxImgDeal(File img, GrayMethod useMethod) throws IOException {
        List<String> lines = new ArrayList<>();
        BufferedImage image = dealImage(ImageIO.read(img), useMethod);
        //因为txt文件一行最多1400列，所以进行步长分析，例如1401+的步长变为2。4201+步长变为3
        int step = (int) Math.ceil(image.getWidth() / 1400.0);
        for (int i = 0; i < image.getHeight(); i++) {
            StringBuilder line = new StringBuilder();
            for (int j = 0; j < image.getWidth(); j += step) {
                int grey = 0;
                for (int k = 0; k < step; k++) {
                    int color = image.getRGB(k + j, i);
                    grey += RGBUtil.ColorToRGB(color).r;
                }
                grey /= step;
                line.append(CHAR_ARR[grey * CHAR_ARR.length / 256]);
            }
            lines.add(line.toString());
        }
        return lines;
    }

    /**
     * @param lines:          所写字符串
     * @param dir:            所写目录
     * @param dealMethodName: 处理方式
     * @param fileName:       文件名称
     * @return: void
     * @author: shijunhao
     * @date: 2021/11/15 16:47
     * @description: 将文件字符画写入
     */
    private void writeTxt(List<String> lines, File dir, String dealMethodName, String fileName) {
        File txt = new File(dir, dealMethodName + fileName + ".txt");
        if (!txt.exists()) {
            try {
                boolean mkf = txt.createNewFile();
                if (!mkf) {
                    System.out.println("创建文件失败！！！");
                    return;
                }
            } catch (IOException e) {
                System.out.println("文件创建失败" + txt.getAbsolutePath());
            }
        }
        FileWriter fileWriter = null;
        BufferedWriter bufferedWriter = null;
        try {
            fileWriter = new FileWriter(txt);
            bufferedWriter = new BufferedWriter(fileWriter);
            for (String line : lines) {
                bufferedWriter.write(line);
                bufferedWriter.newLine();
            }
            System.out.println("写入字符画：\t" + dealMethodName + fileName + "\t成功");
        } catch (IOException e) {
            System.out.println("文件写入失败");
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
                if (fileWriter != null) {
                    fileWriter.close();
                }
            } catch (IOException e) {
                System.out.println("流关闭异常");
            }
        }
    }

    /**
     * @param img:    输入图片
     * @param method: 灰度处理方式
     * @return: java.awt.image.BufferedImage
     * @author: shijunhao
     * @date: 2021/11/15 15:01
     * @description: 将图片灰度处理后返回图片
     */
    private BufferedImage dealImage(BufferedImage img, GrayMethod method) {
        BufferedImage out = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
                int color = img.getRGB(i, j);
                RGB rgb = RGBUtil.ColorToRGB(color);
                int grey = method.getGrey(rgb.r, rgb.g, rgb.b);
                int newColor = RGBUtil.RGBToColor(0, grey, grey, grey);
                out.setRGB(i, j, newColor);
            }
        }
        return out;
    }

    /**
     * @param img:            输出图片
     * @param dir:            输出目录
     * @param dealMethodName: 灰度处理方式名称
     * @return: java.awt.image.BufferedImage
     * @author: shijunhao
     * @date: 2021/11/15 15:01
     * @description: 将灰度处理后的图片输出到文件
     */
    private void writeImage(BufferedImage img, File dir, String dealMethodName, String fileName) {
        File outFile = new File(dir, dealMethodName + fileName);
        try {
            if (!outFile.exists()) {
                boolean mkf = outFile.createNewFile();
                if (!mkf) {
                    System.out.println("创建文件失败！！！");
                    return;
                }
            }
            ImageIO.write(img, fileName.substring(fileName.lastIndexOf('.') + 1), outFile);
        } catch (IOException e) {
            System.out.println("文件创建失败" + outFile.getAbsolutePath());
        }
        System.out.println("写入处理方式：\t" + dealMethodName + fileName + "\t成功");
    }

    private void help() {
        System.out.println("------------------------------------------------------");
        System.out.println("|------------------字符画工具指令帮助-------------------");
        System.out.println("------------------------------------------------------");
        System.out.println("|   1:lg <imgPath> [outputPath]");
        System.out.println("|     1.1:    此功能为将一个图片的各种灰度处理图片输出到");
        System.out.println("|           outputPath生成一个对应图片名称的目录中");
        System.out.println("|     1.2:    默认路径为工作目录");
        System.out.println("------------------------------------------------------");
        System.out.println("|   2:ts <imgPath> [strMethod] [grayMethod] [outputPath]");
        System.out.println("|     2.1:    此功能为将输入图片的字符图片输出到输出目录中");
        System.out.println("|     2.2:    默认路径为工作目录");
        System.out.println("|     2.3:    strMethod 为图片每行转字符串每行处理");
        System.out.println("|       2.3.1:    MAX:取最大值提高步长，windows记事本一行最长为1024");
        System.out.println("|       2.3.2:    ZIP:图片压缩法，将图片的像素缩小到511宽度");
        System.out.println("|       2.3.3:    默认为图片压缩法，此方法更为均匀，但清晰度有损");
        System.out.println("|     2.4:    grayMethod 为灰度处理方式");
        System.out.println("|       2.4.1:    DEAL_AVERAGE:平均值法");
        System.out.println("|       2.4.2:    DEAL_BIGGEST:最大值法");
        System.out.println("|       2.4.3:    DEAL_SMALLEST:最小值法");
        System.out.println("|       2.4.4:    DEAL_POWER:权值法");
        System.out.println("|       2.4.5:    默认为平均值取灰度");
        System.out.println("------------------------------------------------------");
        System.out.println("|   3:help ： 指令帮助");
        System.out.println("------------------------------------------------------");
    }
}
